package xhq.java.test.utilities.types;

import xhq.java.test.utilities.exception.CommonRuntimeException;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

/**
 * @author hq_xu
 * @since 2021/2/2 13:45
 */
public class StringUtils {
    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
    public static final String EMPTY = "";

    private StringUtils() {
    }

    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    public static boolean isBlank(String str) {
        int length;
        if (str != null && (length = str.length()) != 0) {
            for (int i = 0; i < length; ++i) {
                if (!Character.isWhitespace(str.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }

    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    public static boolean equals(String a, String b) {
        if (a == null) {
            return b == null;
        } else {
            return a.equals(b);
        }
    }

    public static boolean equalsIgnoreCase(String a, String b) {
        if (a == null) {
            return b == null;
        } else {
            return a.equalsIgnoreCase(b);
        }
    }

    public static String inputStream2String(InputStream is) {
        if (is == null) {
            return null;
        } else {
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                int i;
                while ((i = is.read()) != -1) {
                    baos.write(i);
                }

                return baos.toString(DEFAULT_ENCODING);
            } catch (Exception ex) {
                throw new CommonRuntimeException(ex);
            }
        }
    }

    public static byte[] inputStream2Bytes(InputStream is) {
        if (is == null) {
            return new byte[0];
        } else {
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                int i;
                while ((i = is.read()) != -1) {
                    baos.write(i);
                }

                return baos.toByteArray();
            } catch (Exception ex) {
                throw new CommonRuntimeException(ex);
            }
        }
    }

    public static String toString(Object obj) {
        if (obj == null) {
            return "null";
        } else if (obj.getClass().isPrimitive()) {
            return String.valueOf(obj);
        } else if (obj instanceof String) {
            return (String) obj;
        } else if ((obj instanceof Number) || (obj instanceof Character) || (obj instanceof Boolean)) {
            return String.valueOf(obj);
        }

        if (obj instanceof Date) {
            return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S")).format(obj);
        } else {
            StringBuilder sb;
            if (obj instanceof Collection) {
                sb = new StringBuilder();
                sb.append("[");
                if (!((Collection) obj).isEmpty()) {
                    for (Object o : (Collection) obj) {
                        sb.append(toString(o)).append(",");
                    }
                    sb.deleteCharAt(sb.length() - 1);
                }
                sb.append("]");
                return sb.toString();
            } else if (obj instanceof Map) {
                Map<Object, Object> map = (Map) obj;
                sb = new StringBuilder();
                sb.append("{");
                if (!map.isEmpty()) {
                    map.forEach((key, value) -> {
                        sb.append(toString(key)).append("->").append(toString(value)).append(",");
                    });
                    sb.deleteCharAt(sb.length() - 1);
                }
                sb.append("}");
                return sb.toString();
            } else {
                sb = new StringBuilder();
                Field[] fields = obj.getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    sb.append(field.getName());
                    sb.append("=");
                    try {
                        Object f = field.get(obj);
                        if (f.getClass() == obj.getClass()) {
                            sb.append(f.toString());
                        } else {
                            sb.append(toString(f));
                        }
                    } catch (Exception ignored) {
                    }

                    sb.append(";");
                }

                return sb.toString();
            }
        }
    }

    public static String trimToNull(String str) {
        String ts = trim(str);
        return isEmpty(ts) ? null : ts;
    }

    public static String trim(String str) {
        return str == null ? null : str.trim();
    }

    public static boolean isEmpty(CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    public static boolean isNotEmpty(CharSequence cs) {
        return !isEmpty(cs);
    }

    /**
     * 把驼峰命名的单词按给定字符进行分隔并全部变成小写，比如 myException -> my-exception
     */
    public static String camelToSplitName(String camelName, String split) {
        if (StringUtils.isEmpty(camelName)) {
            return camelName;
        }
        StringBuilder buf = null;
        for (int i = 0; i < camelName.length(); i++) {
            char ch = camelName.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                if (buf == null) {
                    buf = new StringBuilder();
                    if (i > 0) {
                        buf.append(camelName, 0, i);
                    }
                }
                if (i > 0) {
                    buf.append(split);
                }
                buf.append(Character.toLowerCase(ch));
            } else if (buf != null) {
                buf.append(ch);
            }
        }
        return buf == null ? camelName : buf.toString();
    }
}
